package com.clay.appointment.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.clay.appointment.common.exception.ExceptionEnum;
import com.clay.appointment.common.exception.GlobalException;

import java.util.HashMap;
import java.util.Map;

/**
 * jwt工具类
 *
 * @author Yeung Wah
 * @since 2021/5/31
 */
public class TokenUtils {
    /**
     * 密钥
     */
    private static final String SECRET = "ZGVybWF0b2dseXBoaWNzdW5jb3B5cmlnaHRhYmxlc21pc2Nvbmp1Z2F0ZWRseQ==";
    /**
     * 发布人
     */
    private static final String ISSUER = "clay";
    /**
     * 超时时间 （毫秒）
     */
    private static final Long TIMEOUT = 1000 * 60 * 20L;
    /**
     * 加密算法
     */
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET);
    /**
     * decoder
     */
    private static final JWTVerifier VERIFIER = JWT.require(ALGORITHM).withIssuer(ISSUER).build();

    /**
     * 加密
     *
     * @param parameter 参数
     * @return token
     */
    public static String encode(Map<String, String> parameter) {
        return JWT.create()
                .withClaim("ip", RequestContextUtils.getRemoteAddr())
                .withIssuer(ISSUER)
                .withPayload(parameter)
                .sign(ALGORITHM);
    }

    /**
     * 解密
     *
     * @param token token
     * @return 参数
     */
    public static Map<String, String> decode(String token) {
        DecodedJWT verify = null;
        try {
            verify = VERIFIER.verify(token);
        } catch (JWTVerificationException e) {
            GlobalException.throwOut(ExceptionEnum.AUTH_FAILED);
        }

        Map<String, Claim> claims = verify.getClaims();
        Long encodeTime = claims.get("encodeTime").asLong();
        if (System.currentTimeMillis() - encodeTime > TIMEOUT) {
            GlobalException.throwOut(ExceptionEnum.AUTH_FAILED);
        }

        Map<String, String> map = new HashMap<>();
        claims.forEach((k, v) -> map.put(k, v.asString()));
        map.remove("ip");
        map.remove("iss");

        return map;
    }

    /**
     * 校验
     *
     * @param token token
     * @return 状态
     */
    public static boolean verify(String token) {
        DecodedJWT verify;
        try {
            verify = VERIFIER.verify(token);
        } catch (JWTVerificationException e) {
            return false;
        }

        Map<String, Claim> claims = verify.getClaims();
        Long encodeTime = claims.get("encodeTime").asLong();

        return System.currentTimeMillis() - encodeTime < TIMEOUT;
    }
}